/****************************************************************************
 *  _____       ______  _____
 * |_   _|     |  ____|/ ____|
 *   | |  _ __ | |__  | (___    Institute of Embedded Systems
 *   | | | '_ \|  __|  \___ \   Zürcher Hochschule für Angewandte
 *  _| |_| | | | |____ ____) |  Wissenschaften
 * |_____|_| |_|______|_____/   8401 Winterthur, Switzerland
 *
 ****************************************************************************
 *
 * @version $Rev: 162 $
 * @author  $Author: bacr $
 * @date    $Date: 2013-11-06 09:10:44 +0100 (mer., 06 nov. 2013) $
 *
 ***************************************************************************/

#ifndef __PTP2_TYPES_H__
#define __PTP2_TYPES_H__

#include <stdint.h>
#include <stdbool.h>

#define PTP2_PORT_IDENTITY_LEN          10
#define PTP2_CLOCK_IDENTITY_LEN         8
#define PTP2_PORT_NUMBER_LEN            2
#define PTP2_CORRECTION_LEN             8

#define PTP2_TIMESTAMP_LEN              10
#define PTP2_TIMESTAMP_SECONDS_LEN      6
#define PTP2_TIMESTAMP_NANOSECONDS_LEN  4

#define PTP2_TIMESTAMP_SECONDS_NTOH(x)      (((uint64_t) x.seconds[0]) << 40 | ((uint64_t) x.seconds[1]) << 32 | ((uint64_t) x.seconds[2]) << 24 | ((uint64_t) x.seconds[3]) << 16 | ((uint64_t) x.seconds[4]) << 8 | ((uint64_t) x.seconds[5]))
#define PTP2_TIMESTAMP_NANOSECONDS_NTOH(x)  (x.nanoseconds[0] << 24 | x.nanoseconds[1] << 16 | x.nanoseconds[2] << 8 | x.nanoseconds[3])

#define PTP2_TIMESTAMP_SECONDS_HTON(x,y)    ptp2_timestamp_seconds_hton(x, y)

/*
#define ptp2_port_identity_t        union {                                                      \
                                        uint8_t         port_identity[PTP2_PORT_IDENTITY_LEN];   \
                                        struct {                                                 \
                                            uint8_t     clock_identity[PTP2_CLOCK_IDENTITY_LEN]; \
                                            uint16_t    port_number;                             \
                                        };                                                       \
                                    }

#define ptp2_timestamp_t            union {                                                             \
                                        uint8_t         timestamp[PTP2_TIMESTAMP_LEN];                  \
                                        struct {                                                        \
                                            uint8_t     seconds[PTP2_TIMESTAMP_SECONDS_LEN];            \
                                            uint8_t     nanoseconds[PTP2_TIMESTAMP_NANOSECONDS_LEN];    \
                                        };                                                              \
                                    }

#define ptp2_clock_quality_t        union {                             \
                                        uint32_t        quality;        \
                                        struct {                        \
                                            uint8_t     class;          \
                                            uint8_t     accuracy;       \
                                            uint16_t    log_variance;   \
                                        };                              \
                                    }
*/


/** PTP port state definitions */
typedef enum {
    PTP2_PORT_STATE_NOT_DEFINED,
    PTP2_PORT_STATE_INITIALIZING,
    PTP2_PORT_STATE_FAULTY,
    PTP2_PORT_STATE_DISABLED,
    PTP2_PORT_STATE_LISTENING,
    PTP2_PORT_STATE_PRE_MASTER,
    PTP2_PORT_STATE_MASTER,
    PTP2_PORT_STATE_PASSIVE,
    PTP2_PORT_STATE_UNCALIBRATED,
    PTP2_PORT_STATE_SLAVE
} ptp2_port_state_t;

typedef enum {
    PTP2_BMC_A_BETTER_B                     = 1,
    PTP2_BMC_B_BETTER_A                     = 2,
    PTP2_BMC_A_BETTER_B_TOPOLOGY            = 3,
    PTP2_BMC_B_BETTER_A_TOPOLOGY            = 4,
    PTP2_BMC_A_SAME_B                       = 5,
    PTP2_BMC_MSG_FROM_SELF                  = 6,      /** error-1 */
    PTP2_BMC_DUPLICATED_MSG                 = 7       /** error-2 */
} ptp2_bmc_algorithm_result_t;

typedef enum  {
    PTP2_TIME_SOURCE_ATOMIC_CLOCK           = 0x10,
    PTP2_TIME_SOURCE_GPS                    = 0x20,
    PTP2_TIME_SOURCE_TERRESTRIAL_RADIO      = 0x30,
    PTP2_TIME_SOURCE_PTP                    = 0x40,
    PTP2_TIME_SOURCE_NTP                    = 0x50,
    PTP2_TIME_SOURCE_HAND_SET               = 0x60,
    PTP2_TIME_SOURCE_OTHER                  = 0x90,
    PTP2_TIME_SOURCE_INTERNAL_OSCILLATOR    = 0xA0
} ptp2_time_source_t;


typedef enum {
    PTP2_ADDRESS_NONE = 0,
    PTP2_ADDRESS_LAYER2,
    PTP2_ADDRESS_IPV4,
    PTP2_ADDRESS_IPV6
} ptp2_address_type_t;

typedef enum {
    A_BIGGER_B  = 1,
    A_SAME_B    = 0,
    A_SMALLER_B = -1
} ptp2_compare_result_t;

typedef struct {
    uint8_t         raw[PTP2_CLOCK_IDENTITY_LEN];
} ptp2_clock_identity_t;

typedef union {
    uint8_t         raw[PTP2_PORT_IDENTITY_LEN];
    struct {
        ptp2_clock_identity_t   clock_identity;
        uint16_t                port_number;
    };
} ptp2_port_identity_t;

typedef union {
    uint8_t         raw[PTP2_CORRECTION_LEN];
    int64_t         nanoseconds;
} ptp2_correction_t;

typedef union {
    uint8_t         raw[PTP2_TIMESTAMP_LEN];
    struct {
        uint8_t     seconds[PTP2_TIMESTAMP_SECONDS_LEN];
        uint8_t     nanoseconds[PTP2_TIMESTAMP_NANOSECONDS_LEN];
    };
} ptp2_timestamp_t;

typedef union {
    uint32_t        raw;
    struct {
        uint8_t     class;
        uint8_t     accuracy;
        uint16_t    offset_scaled_log_variance;
    };
} ptp2_clock_quality_t;

typedef struct {
    int64_t         nanoseconds;
} ptp2_time_interval;

extern const ptp2_port_identity_t   PTP2_PORT_IDENTITY_ALL;
extern const ptp2_clock_identity_t  PTP2_CLOCK_IDENTITY_ALL;
extern const uint16_t               PTP2_PORT_NUMBER_ALL;
extern const ptp2_correction_t      PTP2_CORRECTION_NULL;

ptp2_compare_result_t ptp2_clock_identity_compare(const ptp2_clock_identity_t *clock_identity_a, const ptp2_clock_identity_t *clock_identity_b);
ptp2_compare_result_t ptp2_port_identity_compare(const ptp2_port_identity_t *port_identity_a, const ptp2_port_identity_t *port_identity_b);
uint32_t ptp2_miliseconds_log_interval(int8_t log_interval);

void ptp2_timestamp_seconds_hton(uint64_t num, uint8_t *arr);

#endif

